package org.example.service.impl;

import org.example.dao.EmpDao;
import org.example.pojo.Emp;
import org.example.service.BService;
import org.example.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * ClassName: EmpServiceImpl
 * Package: org.example.service.impl
 * Description:
 *
 * @Author wanghao
 * @Create 2024-07-09 9:46
 * @Version 1.0
 */
@Transactional
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpDao empDao;

    //    @Transactional
    @Override
    public void updateEmp1AndEmp2(Emp emp1, Emp emp2) {
        empDao.updateEmpSalary(emp1.getEmpId(), emp1.getSalary());
        empDao.updateEmpDeptNo(emp2.getEmpId(), emp2.getDeptNo());
    }

    // 事务属性：只读
    @Transactional(readOnly = true)
    @Override
    public Emp getEmpById(Integer id) {
        return empDao.getEmpByEmpId(id);
    }

    // 事务属性：超时
    @Transactional(timeout = 10)
    @Override
    public Emp getEmpById2(Integer id) {
        Emp emp = empDao.getEmpByEmpId(id);

        return emp;
    }

    // 演示证明spring默认只针对运行时异常才会回滚，如果是编译器异常是不会回滚的
//    @Transactional
    @Override
    public Emp getEmpById3(Integer id) throws IOException {
        Emp emp = empDao.getEmpByEmpId(id);
//        throw new IOException("故意抛出一个编译器异常");  // committing
        throw new RuntimeException("故意抛出一个运行时异常");  // Rolling back
//        return emp;
    }


    // 演示设置所有的异常都回滚，不论是编译期还是运行时
//    @Transactional(rollbackFor = Exception.class)
    // 所有的异常都要回滚，除了FileNotFoundException
    @Transactional(rollbackForClassName = "java.lang.Exception", noRollbackFor = java.io.FileNotFoundException.class)
    @Override
    public Emp getEmpById4(Integer id) throws IOException {
        Emp emp = empDao.getEmpByEmpId(id);
        //throw new IOException("故意抛出一个编译器异常");  // committing, 添加了rollbackFor,就变成了Rolling back
        throw new FileNotFoundException("故意抛出一个文件找不到的异常");  // committing"
//        throw new RuntimeException("故意抛出一个运行时异常");  // Rolling back
//        return emp;
    }


    /*
        事务的四大特性：原子性 一致性 隔离性 永久性(持久性)
        事务的三大并发问题：脏读、不可重复读、幻读
        事务的隔离级别：读未提交、读已提交、可重复读、串行化
        spring是支持数据库事务的四大隔离级别的
     */

    @Transactional(isolation = Isolation.SERIALIZABLE)
    @Override
    public void oper1() {
        System.out.println("hello world");
        empDao.updateEmpSalary(1, 120);
        empDao.updateEmpSalary(1, 678);
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    @Override
    public void oper2() {
        Emp emp = empDao.getEmpByEmpId(1);
        System.out.println(emp);

        emp = empDao.getEmpByEmpId(1);
        System.out.println(emp);

        emp = empDao.getEmpByEmpId(1);
        System.out.println(emp);

        emp = empDao.getEmpByEmpId(1);
        System.out.println(emp);
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    @Override
    public void oper3() {
        System.out.println("hello world");
        // 串行化时用的是行级锁，所以只有操作同一行的数据才能实现
        empDao.updateEmpSalary(1, 25000);
        System.out.println("hello world");
    }

    @Autowired
    private BService bService;

    // 演示事务的传播行为
    @Override
    public void methodA() {
        empDao.updateEmpSalary(1, 6700);
        bService.methodB();
    }
}
